import warnings
warnings.warn("qturboframe.public_ui.ucf_h_ui.edit_grid模块已被废弃，替代模块为qturboframe.public_ui.h_ui.edit_grid", DeprecationWarning)

import re

from qturboframe.lib.report.log import logger
from qturboframe.lib.ranorex.exceptions import CsClientError
from qturboframe.lib.ranorex.web_element.div_tag import DivTag
from qturboframe.lib.ranorex.web_element.span_tag import SpanTag
from qturboframe.lib.ranorex.web_element.th_tag import ThTag
from qturboframe.lib.ranorex.web_element.td_tag import TdTag
from ..ucf_base_element import BaseElement
from .page import Page
from .select import Select
from .input_type import InputType
from .type_field import TypeField
from .calendar import Calendar
from .base_table import BaseTable


class EditGrid(BaseElement):
    '''
    可编辑表格操作类

    :Attributes:
     - _page: 当前表格的分页栏对象
    '''

    __SELECT_SINGLE_CLASS = r'h-select-single'
    __SELECT_MULTIPLE_CLASS = r'h-select-multiple'
    __INPUT_TYPE_CLASS = r'h-input-wrapper'
    __TYPE_FIELD_CLASS = r'h-typefield'
    __CALENDAR_CLASS = r'h-date-picker'

    _page = Page
    _control_div = DivTag

    def __init__(self, element_para, father=None, timeout=10000):
        super().__init__(element_para, father, timeout)
        self._element = DivTag(self._element.control)
        self.head_table = BaseTable(
            {'xpath': './div/div[@class=\'h-editgird-header\']/table'}, self._element, self.timeout)
        self.body_table = BaseTable(
            {'xpath': './div/div[@class=\'h-editgird-body\']/table'}, self._element, self.timeout)
        self.page()

    def page(self, idname=None, father=None):
        '''
        获取hui表格分页栏对象

        :Args:
         - idname: 分页栏的定位条件，字典类型：{'元素查找方式':'元素查找语句', '辅助属性':'辅助属性值'}
         - father: 分页栏的祖先级元素，可以给分页栏查找限定范围，这样就不需要在整个页面中查找

        :Example:
         - 例: editgrid.page({'xpath':'./following-sibling::ul[@class="h-page"]'})
        '''
        if father is None:
            father = self.element
        if idname:
            self._page = Page(idname, father, 0.1)
        else:
            self._page = Page(
                {'xpath':'./following-sibling::ul[@class~\'h-page\']'}, father, 0.1)
        return self._page

    def get_cell(self, table_dict, title_name, turn_page=False):
        '''
        根据单元格列名和单元格内容查找可编辑表格的单元格

        :Args:
         - table_dict: 单元格列名和单元格内容，字典类型，例：{列名1:内容1, 列名2:内容2}
         - title_name: 查找的单元格列名
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Returns:
            返回查找的单元格

        :Example:
         - 例: cell = editgrid.get_cell({'姓名':'admin', '年龄':'25'}, '工号', True)
        '''
        logger.info('开始表格行号查询')
        # 将表格翻至首页，然后进行逐页查找
        if self._page.exist():
            self._page.to_first()
        # 获取列名列表
        title_list = self.head_table.get_title_list()
        logger.debug('表格显示列名：' + str(title_list))
        row = self._get_row_index(title_list, table_dict, turn_page)
        logger.debug('表格行号查询结束！')
        if row == 0:
            raise CsClientError('未根据查找条件找到表格行！')
        logger.debug('开始表格单元格查询')
        # 根据列名和行数查找单元格
        table_cell = self.__get_cell(title_list, title_name, row)
        logger.debug('单元格查询结束！')
        return table_cell

    def select_rows(self, table_dict):
        '''
        在当前页根据单元格列名和单元格内容勾选行

        :Args:
         - table_dict: 单元格列名和单元格内容，字典类型，例：{列名1:内容1, 列名2:内容2}

        :Example:
         - 例: editgrid.select_rows({'姓名':'admin, manager'})
        '''
        re_checked = 'h-checkbox-checked'
        # 表格数据检查
        key_list = list(table_dict.keys())
        for key in key_list:
            if table_dict.get(key) == '-':
                table_dict.pop(key)
        if not table_dict:
            logger.debug('表格查询条件为空，不勾选！')
            return
        elif table_dict.get('_all_'):
            logger.info('当前表格页全选！')
            self.select_all()
        else:
            logger.info('开始表格行号查询')
            # 获取列名列表
            title_list = self.head_table.get_title_list()
            logger.debug('表格显示列名：' + str(title_list))
            row_list = self.__get_row_indexes(title_list, table_dict)
            logger.debug('表格行号查询结束！')
            logger.debug('开始勾选表格行！')
            tr_list = self.body_table.get_tr_list()
            for row in row_list:
                td = TdTag(tr_list[int(row - 1)].find_elements_by_attribute(
                    'xpath', './/td', timeout=self.timeout)[0].control)
                span = SpanTag(td.find_element_by_attribute(
                    'xpath', './/label[@class~\'h-checkbox-wrapper\']/span[@class~\'h-checkbox\']',
                    timeout=self.timeout).control)
                if not re.search(re_checked, span.get_attribute('class')):
                    span.secure_click()
            logger.debug('勾选表格行结束！')

    def select_all(self):
        '''
        当前页表格行全选

        :Example:
         - 例: editgrid.select_all()
        '''
        re_checked = 'h-checkbox-checked'
        th = ThTag(self.head_table.element.find_elements_by_attribute(
            'xpath', './/thead/tr/th', timeout=self.timeout)[0].control)
        span = SpanTag(th.find_element_by_attribute(
            'xpath', './/label[@class~\'h-checkbox-wrapper\']/span[@class~\'h-checkbox\']',
            timeout=self.timeout).control)
        if not re.search(re_checked, span.get_attribute('class')):
            span.secure_click()

    def auto_fill(self, inputdata:dict, row=0):
        '''
        hui可编辑表格自动填充功能

        :Args:
         - inputdata: 输入数据，需要定位的表格抬头和待输入文本
         - row: 对表格的第几行进行填充，默认最后一行

        :Raises:
            SeleniumError: 可编辑表格填充或校验出错

        :Example:
         - 例: editgrid.auto_fill({'姓名':'admin','年龄':'25','工号':'asdf1234'})
        '''
        # 获取列名列表
        title_list = self.head_table.get_title_list()
        # 获取填充单元格列表
        td_list = self.body_table.get_cell_list_in_row(row)
        for key, value in inputdata.items():
            if value == '-':
                continue
            value = value.split(',')
            td_index = title_list.index(key)
            self._control_div = DivTag(td_list[td_index].find_element_by_attribute(
                'xpath', './/div[@class~\'h-editgird-cell\']/div[@class~\'dbClass\']/div',
                timeout=self.timeout).control)
            # 确定类型
            control_type_list = self.__confirm_type()
            if len(control_type_list) > 1:
                templist = list()
                for i in range(0, len(control_type_list)):
                    templist.append([value[i]])
                value = templist
            elif len(control_type_list) == 0:
                continue
            else:
                value = [value]
            # 识别控件并执行
            for i, control_type in enumerate(control_type_list):
                # 根据控件类型选择控件操作
                if control_type == self.__INPUT_TYPE_CLASS:
                    logger.debug(key + '：文本框')
                    self.__deal_input_type(key, value[i])
                elif control_type == self.__TYPE_FIELD_CLASS:
                    logger.debug(key + '：金额框')
                    self.__deal_type_field(key, value[i])
                elif control_type == self.__SELECT_SINGLE_CLASS:
                    logger.debug(key + '：单选下拉框')
                    self.__deal_select_single(key, value[i])
                elif control_type == self.__SELECT_MULTIPLE_CLASS:
                    logger.debug(key + '：复选下拉框')
                    self.__deal_select_multiple(key, value[i])
                elif control_type == self.__CALENDAR_CLASS:
                    logger.debug(key + '：日历控件')
                    self.__deal_calendar(key, value[i])

    def _get_row_index(self, title_list, table_dict, turn_page=False):
        key_list = list(table_dict.keys())
        logger.debug('表格查找列名索引：' + str(key_list))
        # 以输入数据作为索引查找表格行数
        row_list = list()
        rows = 0
        for i, key in enumerate(key_list):
            text_list = list()
            temp_list = list()
            # 获取指定列内容列表
            if len(text_list) == 0:
                try:
                    title_index = title_list.index(key)
                    logger.debug('第' + str(title_index + 1) + '列，名称：' + key)
                except:
                    logger.debug('表格中没有列名：' + key)
                else:
                    text_list = self.body_table.get_text_list(len(title_list), int(title_index + 1))
            if i == 0:
                rows = len(text_list)
                logger.debug('当前页显示行数：' + str(rows))
                row_list = list(range(1, rows + 1))
            content_list = table_dict[key].split(',')
            for j in row_list:
                for k in content_list:
                    if text_list[j - 1] == k:
                        logger.debug('要查找的内容：' + k)
                        logger.debug('第' + str(j) + '行，内容：' + text_list[j - 1])
                        temp_list.append(j)
            row_list = temp_list
            if len(row_list) == 0:
                break
        # 未找到数据行则进行表格翻页
        if len(row_list) > 0:
            return row_list[0]
        else:
            if turn_page:
                if self._page.exist():
                    if self._page.is_last():
                        raise CsClientError("未找到目标数据行！")
                    else:
                        self._page.to_next()
                        logger.debug("翻下一页查找。")
                        return self._get_row_index(title_list, table_dict, turn_page)
                else:
                    raise CsClientError("未找到目标数据行！")
            else:
                raise CsClientError("未找到目标数据行！")

    def __get_row_indexes(self, title_list, table_dict, turn_page=False):
        key_list = list(table_dict.keys())
        logger.debug('表格查找列名索引：' + str(key_list))
        # 以输入数据作为索引查找表格行数
        row_list = list()
        rows = 0
        for i, key in enumerate(key_list):
            text_list = list()
            temp_list = list()
            # 获取指定列内容列表
            if len(text_list) == 0:
                try:
                    title_index = title_list.index(key)
                    logger.debug('第' + str(title_index + 1) + '列，名称：' + key)
                except:
                    logger.debug('表格中没有列名：' + key)
                else:
                    text_list = self.body_table.get_text_list(len(title_list), int(title_index + 1))
            if i == 0:
                rows = len(text_list)
                logger.debug('当前页显示行数：' + str(rows))
                row_list = list(range(1, rows + 1))
            content_list = table_dict[key].split(',')
            for j in row_list:
                for k in content_list:
                    if text_list[j - 1] == k:
                        logger.debug('要查找的内容：' + k)
                        logger.debug('第' + str(j) + '行，内容：' + text_list[j - 1])
                        temp_list.append(j)
            row_list = temp_list
            if len(row_list) == 0:
                break
        # 翻页查找
        if turn_page:
            if self._page.exist():
                if not self._page.is_last():
                    self._page.to_next()
                    logger.debug("翻下一页查找。")
                    row_list.extend(self.__get_row_indexes(title_list, table_dict, turn_page))
        if len(row_list) > 0:
            return row_list
        else:
            return []

    def __get_cell(self, title_list, title_name, row):
        table_cell = None
        if row <= 0:
            raise CsClientError('表格行号出错！')
        # 获取数据表格单元格列表
        cell_list = self.body_table.get_cell_list()
        tr_list = self.body_table.get_tr_list()
        rows = len(tr_list)
        # 当前表格显示的行数
        logger.debug(
            '当前页显示行数：{}/{}={}'.format(len(cell_list), len(title_list), rows))
        try:
            title_index = title_list.index(title_name)
            logger.debug('第' + str(title_index + 1) + '列，名称：' + title_name)
        except ValueError:
            raise CsClientError('列名不存在！')
        else:
            cell_index = int(title_index + (len(title_list) * (row - 1)))
            table_cell = cell_list[cell_index]
        return table_cell

    def __confirm_type(self):
        # 获取控件层div的class属性
        div_class_list = self._control_div.get_attribute('class').split(' ')
        # 判定控件类型
        if self.__INPUT_TYPE_CLASS in div_class_list:
            self._elements = DivTag(self._control_div.find_element_by_attribute(
                'xpath', './/div[@class~\'h-input-wrapper\']', timeout=self.timeout).control)
            return [self.__INPUT_TYPE_CLASS]
        elif self.__TYPE_FIELD_CLASS in div_class_list:
            self._elements = DivTag(self._control_div.find_element_by_attribute(
                'xpath', './/div[@class=\'h-typefield\' or @class~\' h-typefield \' or '
                         '@class~\'^h-typefield \' or @class~\' h-typefield$\']',
                timeout=self.timeout).control)
            return [self.__TYPE_FIELD_CLASS]
        elif self.__SELECT_SINGLE_CLASS in div_class_list:
            self._elements = DivTag(self._control_div.find_element_by_attribute(
                'xpath', './/div[@class~\'h-select-single\']', timeout=self.timeout).control)
            return [self.__SELECT_SINGLE_CLASS]
        elif self.__SELECT_MULTIPLE_CLASS in div_class_list:
            self._elements = DivTag(self._control_div.find_element_by_attribute(
                'xpath', './/div[@class~\'h-select-multiple\']', timeout=self.timeout).control)
            return [self.__SELECT_MULTIPLE_CLASS]
        elif self.__CALENDAR_CLASS in div_class_list:
            self._elements = DivTag(self._control_div.find_element_by_attribute(
                'xpath', './/div[@class=\'h-date-picker\']', timeout=self.timeout).control)
            return [self.__CALENDAR_CLASS]
        else:
            logger.warn('非表单控件')
            return []

    def __deal_input_type(self, key, value):
        '''
        处理hui文本框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        input_type = InputType(self._elements)
        text = value[0]
        logger.info(key + '进行文本框填充。')
        input_type.set_value(text)
        return

    def __deal_type_field(self, key, value):
        '''
        处理hui金额框

        :Args:
         - key: 控件名称
         - value: 填充值
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 填充或判断值是出错
        '''
        type_field = TypeField(self._elements)
        text = value[0]
        logger.info(key + '进行文本框填充。')
        type_field.set_value(text)

    def __deal_select_single(self, key, value):
        '''
        处理hui单选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select = Select(self._elements)
        text = value[0]
        logger.info(key + '进行单选下拉框选择。')
        select.set_value_for_single(text, self.timeout)

    def __deal_select_multiple(self, key, value):
        '''
        处理hui多选下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        select = Select(self._elements)
        logger.info(key + '进行复选下拉框选择。')
        select.set_value_for_multiple(value)

    def __deal_calendar(self, key, value):
        '''
        处理hui日历下拉框

        :Args:
         - key: 控件名称
         - value: 下拉选项，list类型
         - flag: 操作标记

        :Returns:
            判断失败返回False

        :Raises:
            SeleniumError: 选择或判断值是出错
        '''
        calendar = Calendar(self._elements)
        logger.info(key + '进行日期选择。')
        calendar.set_value(value[0])
